package me.lwn.auth.common.crud;

import me.lwn.auth.common.PageRequest;
import me.lwn.auth.common.PageResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseManager<T, ID> {

    public PageResponse<T> page(PageRequest params) {
        Specification<T> specification = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            params.getSearchFilters().forEach(searchFilter -> {
                switch (searchFilter.getMatchType()) {
                    case EQ:
                        list.add(criteriaBuilder.equal(root.get(searchFilter.getPropertyName()), searchFilter.getValue()));
                        break;
                    case GT:
                        list.add(criteriaBuilder.gt(root.get(searchFilter.getPropertyName()), Integer.parseInt(searchFilter.getValue())));
                        break;
                    case LIKE:
                        list.add(criteriaBuilder.like(root.get(searchFilter.getPropertyName()), "%" + searchFilter.getValue() + "%"));
                        break;
                    case LT:
                        list.add(criteriaBuilder.lt(root.get(searchFilter.getPropertyName()), Integer.parseInt(searchFilter.getValue())));
                        break;
                    case GTD:
                        list.add(criteriaBuilder.greaterThan(root.get(searchFilter.getPropertyName()).as(String.class), searchFilter.getValue()));
                        break;
                    case LTD:
                        list.add(criteriaBuilder.lessThan(root.get(searchFilter.getPropertyName()).as(String.class), searchFilter.getValue()));
                        break;
                }
            });
            Predicate[] predicates = new Predicate[list.size()];
            list.toArray(predicates);
            return criteriaBuilder.and(predicates);
        };
        Page<T> pages = getRepository().findAll(specification, org.springframework.data.domain.PageRequest.of((int) (params.getPage() - 1), (int) params.getSize()));
        PageResponse<T> pageResponse = new PageResponse<>(params.getPage(), pages.getSize());
        pageResponse.setTotal(pages.getTotalElements());
        pageResponse.setList(pages.getContent());
        return pageResponse;
    }

    protected abstract BaseRepository<T, ID> getRepository();
}
